// 引入核心模块
var http = require('http')

var path = require("path")
var fse = require("fs-extra")
var multiparty = require("multiparty")

// 创建服务器(API返回的是一个实例)
var server = http.createServer()

// 大文件目录
const UPLOAD_DIR = path.resolve(__dirname, "..", "target")

const resolvePost = req =>
	new Promise(resolve => {
		let chunk = "";
		req.on("data", data => {
			chunk += data;
		});
		req.on("end", () => {
			resolve(JSON.parse(chunk));
		});
	});

// 写入文件流
const pipeStream = (path, writeStream) =>
	new Promise(resolve => {
		const readStream = fse.createReadStream(path);
		readStream.on("end", () => {
			fse.unlinkSync(path);
			resolve();
		});
		readStream.pipe(writeStream);
	});


// 合并切片
const mergeFileChunk = async (filePath, filename, size) => {
	const chunkDir = path.resolve(UPLOAD_DIR, 'chunkDir' + filename);
	const chunkPaths = await fse.readdir(chunkDir);
	// 根据切片下标进行排序
	// 否则直接读取目录的获得的顺序会错乱
	chunkPaths.sort((a, b) => a.split("-")[1] - b.split("-")[1]);
	// chunkPaths 为拿到的所有切片,并将其排好序
	// 并发写入文件
	await Promise.all(
		chunkPaths.map((chunkPath, index) =>
			pipeStream(
				path.resolve(chunkDir, chunkPath),
				// 根据 size 在指定位置创建可写流
				fse.createWriteStream(filePath, {
					start: index * size,
				})
			)
		)
	);
	// 合并后删除保存切片的目录
	fse.rmdirSync(chunkDir);
};

// 删除所有文件
// delete all the files
const deleteFiles = async (req, res) => {
  // await fse.remove(path.resolve(UPLOAD_DIR));
	res.end(
    JSON.stringify({
      code: 0,
      message: "file delete success"
    })
  );
}


// 监听客户端发起的请求
server.on('request', async (req, res) => {
	// 客户端请求路径
	console.log(`客户端请求路径为：${req.url}`)

	// 处理跨域
	res.setHeader("Access-Control-Allow-Origin", "*")
	res.setHeader("Access-Control-Allow-Headers", "*")
	res.setHeader('Content-Type', 'text/plain;charset=utf-8');
	if (req.method === "OPTIONS") {
		console.log("req.methods ====>>>>", req.method)
		res.status = 200;
		res.end();
		return;
	}

	// 拟路由
	switch (req.url) {

		case '/': {
			// res.write('欢迎来到首页')
			res.end(JSON.stringify({ code: 200, msg: `this is Index` }));
			break;
		}

		// 上传文件路由
		case '/upload': {
			const multipart = new multiparty.Form();

			// 解析传入的表单数据请求 
			multipart.parse(req, async (err, fields, files) => {
				if (err) {
					return;
				}
				const [chunk] = files.chunk;
				const [hash] = fields.hash;
				const [filename] = fields.filename;
				// 创建临时文件夹用于临时存储 chunk
				// 添加 chunkDir 前缀与文件名做区分
				const chunkDir = path.resolve(UPLOAD_DIR, 'chunkDir' + filename);
		
				// fs.existsSync () 方法用于同步检查给定路径中是​​否已存在文件。它返回一个布尔值，指示文件的存在。
				if (!fse.existsSync(chunkDir)) {
					// 不存在，创建目录
					await fse.mkdirs(chunkDir);
				}
		
				// fs-extra 的 rename 方法 windows 平台会有权限问题
				// @see https://github.com/meteor/meteor/issues/7852#issuecomment-255767835
				await fse.move(chunk.path, `${chunkDir}/${hash}`);
				res.end("文件上传完成")
			});
			break
		}

		// 文件合并
		case '/merge': {
			const data = await resolvePost(req);
			const { filename, size } = data;
			const filePath = path.resolve(UPLOAD_DIR, `${filename}`);
			await mergeFileChunk(filePath, filename, size);
			res.end(
				JSON.stringify({
					code: 0,
					message: "file merged success"
				})
			);
			break
		}

		case '/delete': {
			deleteFiles(req, res)
		}
	}
})


// 绑定端口号(3000)
server.listen(3000, () => {
	console.log(`服务器启动成功,等待客户端请求...`)
})